#include "kernel/syscall/sys.h"
#include "kernel/vfs/vfs.h"
#include "libs/errno.h"
#include "libs/lib.h"
#include "kernel/vfs/fat32.h"
#include "libs/fcntl.h"
#include "libs/sched.h"
#include "kernel/driver/keyboarddriver.h"

extern "C" uint64_t no_system_call(StackFrame* regs)
{

    LOG_ERROR("123123\n");
	LOG_INFO("no_system_call is calling,NR:%#04x\n",regs->RAX);

	return -1;
}


extern "C" uint64_t sys_printf(StackFrame* regs)
{
    
	LOG_INFO((char *)regs->RDI);

    

	return 1;
}


extern "C" uint64_t sys_open(StackFrame* regs){

    char* filename = (char*)regs->RDI;
    uint64_t flags =  regs->RSI;
    char* path = NULL;
    int64_t pathlen = 0;
    int64_t error = 0;
    
    DirEntry* dentry = NULL;
    File* filep = NULL;
    File** f = NULL;

    int fd = -1;
    int i;

    path = new char(PAGE_4K_SIZE);
    if(path == NULL)
        return -ENOMEM;
    memset(path,0,PAGE_4K_SIZE);
    
    pathlen = strnlen_user(filename,PAGE_4K_SIZE);

    if(pathlen <=0 ){

        delete path;
        return -EFAULT;

    }
    else if(pathlen >= PAGE_4K_SIZE)
    {

        delete path;
        return -ENAMETOOLONG;
    }
    
    strncpy_from_user(filename,path,pathlen);

    dentry =  FAT32FILESYSTEM->pathSearch(path,0);

    
    delete path;

    if(dentry != NULL){


    }else{
        LOG_ERROR("can`t find file!\n");
    }
    if(!dentry) return -ENOENT;

    if(dentry->dirInode->attribute == FS_ATTR_DIR)
        return -EISDIR;
    
    if(dentry->dirInode->attribute & FS_ATTR_DEVICE)
    {
        filep = new KbFile();
    }
    else{

         filep = new FAT32File();

    }

    filep->dentry = dentry;

    filep->mode = flags;

    error =  filep->open(dentry->dirInode,filep);

    

    if(error != 1){

        delete filep;
        return -EFAULT;

    }

    if(filep->mode & O_TRUNC)
    {
        filep->dentry->dirInode->fileSize = 0;
    }

    if(filep->mode & O_APPEND){

        filep->position = filep->dentry->dirInode->fileSize;

    }
    for (size_t i = 0; i < TASK_FILE_MAX; i++)
    {
        /* code */
        if(current->fileHandle[i] == NULL){
            fd = i;
            break;
        }

        if(i == TASK_FILE_MAX){
            
            delete filep;
            return -EMFILE;

        }

    }
    
    current->fileHandle[fd] = filep;
    return fd;
}   




extern "C" uint64_t sys_close(StackFrame* regs){


    int64_t fd = regs->RDI;
    File* filp = NULL;

    if(fd <  0 || fd >= TASK_FILE_MAX)
        return -EBADF;

    filp = current->fileHandle[fd];
    
    if(!filp)
        return -ENOTE;

    if(filp)
        filp->close(filp->dentry->dirInode,filp);

    delete filp;

    current->fileHandle[fd] = NULL;

    return 0;


}


extern "C" uint64_t sys_read(StackFrame* regs){

    int fd = regs->RDI;
    char* buffer = (char*)regs->RSI;
    int64_t count = regs->RDX;

    File* filp = NULL;

    if(fd <  0 || fd >= TASK_FILE_MAX)
        return -EBADF;
    if(count < 0)
        return -EINVAL;

    filp = current->fileHandle[fd];
    

    if(!filp)
        return -ENOTE;
   
    uint64_t ret = filp->read(buffer,count,&filp->position);

    return ret;


}


extern "C" uint64_t sys_write(StackFrame* regs){


    int fd = regs->RDI;
    char* buffer = (char*)regs->RSI;
    int64_t count = regs->RDX;

    File* filp = NULL;

    if(fd <  0 || fd >= TASK_FILE_MAX)
        return -EBADF;
    if(count < 0)
        return -EINVAL;

    filp = current->fileHandle[fd];
    
    if(!filp)
        return -ENOTE;
    
    uint64_t ret = filp->write(buffer,count,&filp->position);

    return ret;
}


extern "C" uint64_t sys_lseek(StackFrame* regs){


    int fd = regs->RDI;
    int64_t offset = regs->RSI;
    int64_t origin = regs->RDX;

    File* filp = NULL;

    if(fd <  0 || fd >= TASK_FILE_MAX)
        return -EBADF;

    filp = current->fileHandle[fd];
    
    if(!filp)
        return -ENOTE;

    uint64_t ret = filp->lseek(offset,origin);

    return ret;
}


extern "C" uint64_t sys_fork(StackFrame* regs){

    return TASKMANAGER->do_fork(regs,0,regs->OLDRSP,0);
}

extern "C" uint64_t sys_vfork(StackFrame* regs){

    return TASKMANAGER->do_fork(regs,CLONE_VM | CLONE_FS,regs->OLDRSP,0);
}


extern "C" uint64_t sys_brk(StackFrame* regs){


   
    uint64_t brk = regs->RDI;
    uint64_t newBrk = PAGE_2M_ALIGN(brk);

    if(newBrk == 0){
        return current->mm->start_brk;
    }

    if(newBrk < current->mm->end_brk)
        return 0;
    
    MEMORY->doBrk(current->mm->end_brk,newBrk - current->mm->end_brk);

    current->mm->end_brk = newBrk;

    return newBrk;
}


extern "C" uint64_t sys_create(StackFrame* regs)
{

    



}


extern "C" uint64_t sys_reboot(StackFrame* regs)
{

    uint64_t cmd = regs->RDI;
    void* arg = (void*)regs->RSI;


    switch (cmd)
    {
    case SYSTEM_REBOOT/* constant-expression */:
        /* code */
        io_out8(0x64,0xfe);
        break;
    case SYSTEM_POWEROFF:

        break;
    
    default:
        break;
    }

    return 0;

}